/*
 * @(#)XmlResult.java $version 2010. 8. 11
 *
 * Copyright 2007-2010 NHN Corp. All rights Reserved. 
 * NHN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 */
package com.nhncorp.usf.core.result.direct;

import java.io.PrintWriter;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import javax.servlet.http.HttpServletResponse;

import com.nhncorp.lucy.web.helper.ServletHelper;
import com.nhncorp.usf.core.config.runtime.ResultPageInfo;
import com.nhncorp.usf.core.util.StringUtil;

/**
 * {@link ResultPageInfos} Path 에 정의된 내용을 내보내는 {@link Result}.
 *
 * @author Web Platform Development Team
 */
@SuppressWarnings("serial")
public class XmlResult extends AbstractDirectResult {
    private static final String SEPARATOR = ",";

    /**
     * 전달된 {@link DataMap} 정보를 {@link ResultPageInfo}  에 적용하여 결과 페이지 내보냄.
     *
     * @param resultPage the page information
     * @param dataMap    the usf result data
     * @throws Exception the Exception
     */
    public void execute(ResultPageInfo resultPage, Map<String, Object> dataMap) throws Exception {
        Properties properties = resultPage.getProperties();
        String srcData = properties.getProperty("src");

        if (StringUtil.isEmpty(srcData)) {
            throw new Exception("src property is not correct");
        }

        HttpServletResponse response = ServletHelper.getResponse();
        response.setContentType("text/xml; charset=" + getPageEncoding());

        String[] splitNames = srcData.split(SEPARATOR);

        PrintWriter out = response.getWriter();
        StringBuffer sb = new StringBuffer();
        sb.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");                                                                                                               
        sb.append("<message type=\"response\" service=\"koreabusinesssupport.developmentplatform.libraryandframework.USF\" ");
        sb.append("version=\"1.0.0\" xmlns:xsi= \"http://www.w3.org/2001/XMLSchema-instance\" xsi:noNamespaceSchemaLocation=\"http://dev.naver.com/xsd/usf/usf-xml-result.xsd\">\n");
        sb.append("<result>\n");

        for (String name : splitNames) {
            String trimName = name.trim();
            sb.append(generateMapTable(dataMap, trimName, 1));
        }

        sb.append("</result>\n");
        sb.append("</message>");
        out.println(sb.toString());
        out.flush();
    }

    /**
     * Generate map table.
     *
     * @param dataMap     the data map
     * @param keyString   the key string
     * @param indentCount the indent count
     * @return the string buffer
     */
    private StringBuffer generateMapTable(Map<String, Object> dataMap, String keyString, int indentCount) {
        StringBuffer sb = new StringBuffer();
        String tap = "";

        for (int i = 0; i < indentCount; i++) {
            tap = tap + "\t";
        }

        sb.append(tap + "<data name=\"" + keyString + "\"");
        Object obj = dataMap.get(keyString);
        generateMapTable(sb, tap, obj, indentCount);
        return sb;
    }
    
    /**
     * Generate map table.
     *
     * @param sb     StringBuffer
     * @param tap   String
     * @param obj Object
     * @param indentCount int
     */
    @SuppressWarnings("unchecked")
	private void generateMapTable(StringBuffer sb, String tap, Object obj, int indentCount) {
        if (obj instanceof Map) {
            sb.append(" type = \"" + getType(obj) + "\" >\n");
            sb.append(generateMapTable((Map<String, Object>) obj, indentCount + 1) + tap + "</data>\n");
        } else if (obj instanceof List) {
            sb.append(" type = \"" + getType(obj) + "\" >\n");
            sb.append(generateListTable((List) obj, indentCount + 1) + tap + "</data>\n");
        } else {
            sb.append(" type = \"" + getType(obj) + "\" >");
            sb.append("<![CDATA[" + obj + "]]></data>\n");
        }
    }

    /**
     * Generate map table.
     *
     * @param dataMap     the data map
     * @param indentCount the indent count
     * @return the string buffer
     */
    private StringBuffer generateTable(Map<String, Object> dataMap, int indentCount) {
        StringBuffer sb = new StringBuffer();

        String tap = "";

        for (int i = 0; i < indentCount; i++) {
            tap = tap + "\t";
        }

        for (Map.Entry<String, Object> entry : dataMap.entrySet()) {
            sb.append(tap + "<data name=\"" + entry.getKey() + "\"");
            Object obj = entry.getValue();
            generateMapTable(sb, tap, obj, indentCount);
        }

        return sb;
    }

    /**
     * Generate list table.
     *
     * @param list the list
     * @param indentCount the indent count
     * @return the string buffer
     */
    @SuppressWarnings("unchecked")
	private StringBuffer generateListTable(List list, int indentCount) {
        StringBuffer sb = new StringBuffer();

        String tap = "";

        for (int i = 0; i < indentCount; i++) {
            tap = tap + "\t";
        }

        for (Object obj : list) {
            if (obj instanceof Map) {
                sb.append(tap + "<item type=\"map\">\n");
                sb.append(generateTable((Map<String, Object>) obj, indentCount + 1));
                sb.append(tap + "</item>\n");
            } else if (obj instanceof List) {
                sb.append(tap + "<item type=\"list\">\n");
                sb.append(generateListTable((List) obj, indentCount + 1));
                sb.append(tap + "</item>\n");
            } else {
                sb.append(tap + "<item type=\"" + getType(obj) + "\">" + "<![CDATA[" + obj + "]]>" + "</item>\n");
            }
        }

        return sb;
    }

    /**
     * Generate map table.
     *
     * @param dataMap the data map
     * @param indentCount the indent count
     * @return the string buffer
     */
    private StringBuffer generateMapTable(Map<String, Object> dataMap, int indentCount) {
        StringBuffer sb = new StringBuffer();
        sb.append(generateTable(dataMap, indentCount));
        return sb;
    }

    /**
     * Gets the type.
     *
     * @param obj the obj
     * @return the type
     */
    private String getType(Object obj) {
        if (obj == null) {
            return "NULL";
        }

        return obj.getClass().getSimpleName();
    }
}
